#include "astyle.h"
#include <algorithm>

namespace astyle {
  static int g_preprocessorCppExternCBrace;
  ASBeautifier::ASBeautifier() {
    waitingBeautifierStack = nullptr;
    activeBeautifierStack = nullptr;
    waitingBeautifierStackLengthStack = nullptr;
    activeBeautifierStackLengthStack = nullptr;
    headerStack = nullptr;
    tempStacks = nullptr;
    squareBracketDepthStack = nullptr;
    blockStatementStack = nullptr;
    parenStatementStack = nullptr;
    braceBlockStateStack = nullptr;
    continuationIndentStack = nullptr;
    continuationIndentStackSizeStack = nullptr;
    parenIndentStack = nullptr;
    preprocIndentStack = nullptr;
    sourceIterator = nullptr;
    isModeManuallySet = false;
    shouldForceTabIndentation = false;
    setSpaceIndentation( 4 );
    setContinuationIndentation( 1 );
    setMinConditionalIndentOption( MINCOND_TWO );
    setMaxContinuationIndentLength( 40 );
    classInitializerIndents = 1;
    tabLength = 0;
    setClassIndent( false );
    setModifierIndent( false );
    setSwitchIndent( false );
    setCaseIndent( false );
    setBlockIndent( false );
    setBraceIndent( false );
    setBraceIndentVtk( false );
    setNamespaceIndent( false );
    setAfterParenIndent( false );
    setLabelIndent( false );
    setEmptyLineFill( false );
    setCStyle();
    setPreprocDefineIndent( false );
    setPreprocConditionalIndent( false );
    setAlignMethodColon( false );
    beautifierFileType = 9;
    headers = new vector<const string*>;
    nonParenHeaders = new vector<const string*>;
    assignmentOperators = new vector<const string*>;
    nonAssignmentOperators = new vector<const string*>;
    preBlockStatements = new vector<const string*>;
    preCommandHeaders = new vector<const string*>;
    indentableHeaders = new vector<const string*>;
  }

  ASBeautifier::ASBeautifier( const ASBeautifier& other ) : ASBase( other ) {
    waitingBeautifierStack = nullptr;
    activeBeautifierStack = nullptr;
    waitingBeautifierStackLengthStack = nullptr;
    activeBeautifierStackLengthStack = nullptr;
    headerStack = new vector<const string*>;
    *headerStack = *other.headerStack;
    tempStacks = copyTempStacks( other );
    squareBracketDepthStack = new vector<int>;
    *squareBracketDepthStack = *other.squareBracketDepthStack;
    blockStatementStack = new vector<bool>;
    *blockStatementStack = *other.blockStatementStack;
    parenStatementStack = new vector<bool>;
    *parenStatementStack = *other.parenStatementStack;
    braceBlockStateStack = new vector<bool>;
    *braceBlockStateStack = *other.braceBlockStateStack;
    continuationIndentStack = new vector<int>;
    *continuationIndentStack = *other.continuationIndentStack;
    continuationIndentStackSizeStack = new vector<int>;
    *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
    parenIndentStack = new vector<int>;
    *parenIndentStack = *other.parenIndentStack;
    preprocIndentStack = new vector<pair<int, int> >;
    *preprocIndentStack = *other.preprocIndentStack;
    beautifierFileType = other.beautifierFileType;
    headers = other.headers;
    nonParenHeaders = other.nonParenHeaders;
    assignmentOperators = other.assignmentOperators;
    nonAssignmentOperators = other.nonAssignmentOperators;
    preBlockStatements = other.preBlockStatements;
    preCommandHeaders = other.preCommandHeaders;
    indentableHeaders = other.indentableHeaders;
    inLineNumber = other.inLineNumber;
    runInIndentContinuation = other.runInIndentContinuation;
    nonInStatementBrace = other.nonInStatementBrace;
    objCColonAlignSubsequent = other.objCColonAlignSubsequent;
    lineCommentNoBeautify = other.lineCommentNoBeautify;
    isElseHeaderIndent = other.isElseHeaderIndent;
    isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent;
    isNonInStatementArray = other.isNonInStatementArray;
    isSharpAccessor = other.isSharpAccessor;
    isSharpDelegate = other.isSharpDelegate;
    isInExternC = other.isInExternC;
    isInBeautifySQL = other.isInBeautifySQL;
    isInIndentableStruct = other.isInIndentableStruct;
    isInIndentablePreproc = other.isInIndentablePreproc;
    sourceIterator = other.sourceIterator;
    currentHeader = other.currentHeader;
    previousLastLineHeader = other.previousLastLineHeader;
    probationHeader = other.probationHeader;
    lastLineHeader = other.lastLineHeader;
    indentString = other.indentString;
    verbatimDelimiter = other.verbatimDelimiter;
    isInQuote = other.isInQuote;
    isInVerbatimQuote = other.isInVerbatimQuote;
    haveLineContinuationChar = other.haveLineContinuationChar;
    isInAsm = other.isInAsm;
    isInAsmOneLine = other.isInAsmOneLine;
    isInAsmBlock = other.isInAsmBlock;
    isInComment = other.isInComment;
    isInPreprocessorComment = other.isInPreprocessorComment;
    isInRunInComment = other.isInRunInComment;
    isInCase = other.isInCase;
    isInQuestion = other.isInQuestion;
    isContinuation = other.isContinuation;
    isInHeader = other.isInHeader;
    isInTemplate = other.isInTemplate;
    isInDefine = other.isInDefine;
    isInDefineDefinition = other.isInDefineDefinition;
    classIndent = other.classIndent;
    isIndentModeOff = other.isIndentModeOff;
    isInClassHeader = other.isInClassHeader;
    isInClassHeaderTab = other.isInClassHeaderTab;
    isInClassInitializer = other.isInClassInitializer;
    isInClass = other.isInClass;
    isInObjCMethodDefinition = other.isInObjCMethodDefinition;
    isInObjCMethodCall = other.isInObjCMethodCall;
    isInObjCMethodCallFirst = other.isInObjCMethodCallFirst;
    isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition;
    isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall;
    isInIndentablePreprocBlock = other.isInIndentablePreprocBlock;
    isInObjCInterface = other.isInObjCInterface;
    isInEnum = other.isInEnum;
    isInEnumTypeID = other.isInEnumTypeID;
    isInLet = other.isInLet;
    modifierIndent = other.modifierIndent;
    switchIndent = other.switchIndent;
    caseIndent = other.caseIndent;
    namespaceIndent = other.namespaceIndent;
    braceIndent = other.braceIndent;
    braceIndentVtk = other.braceIndentVtk;
    blockIndent = other.blockIndent;
    shouldIndentAfterParen = other.shouldIndentAfterParen;
    labelIndent = other.labelIndent;
    isInConditional = other.isInConditional;
    isModeManuallySet = other.isModeManuallySet;
    shouldForceTabIndentation = other.shouldForceTabIndentation;
    emptyLineFill = other.emptyLineFill;
    lineOpensWithLineComment = other.lineOpensWithLineComment;
    lineOpensWithComment = other.lineOpensWithComment;
    lineStartsInComment = other.lineStartsInComment;
    backslashEndsPrevLine = other.backslashEndsPrevLine;
    blockCommentNoIndent = other.blockCommentNoIndent;
    blockCommentNoBeautify = other.blockCommentNoBeautify;
    previousLineProbationTab = other.previousLineProbationTab;
    lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
    lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
    lineBeginsWithComma = other.lineBeginsWithComma;
    lineIsCommentOnly = other.lineIsCommentOnly;
    lineIsLineCommentOnly = other.lineIsLineCommentOnly;
    shouldIndentBracedLine = other.shouldIndentBracedLine;
    isInSwitch = other.isInSwitch;
    foundPreCommandHeader = other.foundPreCommandHeader;
    foundPreCommandMacro = other.foundPreCommandMacro;
    shouldAlignMethodColon = other.shouldAlignMethodColon;
    shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
    shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
    indentCount = other.indentCount;
    spaceIndentCount = other.spaceIndentCount;
    spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
    bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
    colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
    lineOpeningBlocksNum = other.lineOpeningBlocksNum;
    lineClosingBlocksNum = other.lineClosingBlocksNum;
    fileType = other.fileType;
    minConditionalOption = other.minConditionalOption;
    minConditionalIndent = other.minConditionalIndent;
    parenDepth = other.parenDepth;
    indentLength = other.indentLength;
    tabLength = other.tabLength;
    continuationIndent = other.continuationIndent;
    blockTabCount = other.blockTabCount;
    maxContinuationIndent = other.maxContinuationIndent;
    classInitializerIndents = other.classInitializerIndents;
    templateDepth = other.templateDepth;
    squareBracketCount = other.squareBracketCount;
    prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
    prevFinalLineIndentCount = other.prevFinalLineIndentCount;
    defineIndentCount = other.defineIndentCount;
    preprocBlockIndent = other.preprocBlockIndent;
    quoteChar = other.quoteChar;
    prevNonSpaceCh = other.prevNonSpaceCh;
    currentNonSpaceCh = other.currentNonSpaceCh;
    currentNonLegalCh = other.currentNonLegalCh;
    prevNonLegalCh = other.prevNonLegalCh;
  }

  ASBeautifier::~ASBeautifier() {
    deleteBeautifierContainer( waitingBeautifierStack );
    deleteBeautifierContainer( activeBeautifierStack );
    deleteContainer( waitingBeautifierStackLengthStack );
    deleteContainer( activeBeautifierStackLengthStack );
    deleteContainer( headerStack );
    deleteTempStacksContainer( tempStacks );
    deleteContainer( squareBracketDepthStack );
    deleteContainer( blockStatementStack );
    deleteContainer( parenStatementStack );
    deleteContainer( braceBlockStateStack );
    deleteContainer( continuationIndentStack );
    deleteContainer( continuationIndentStackSizeStack );
    deleteContainer( parenIndentStack );
    deleteContainer( preprocIndentStack );
  }

  void ASBeautifier::init( ASSourceIterator* iter ) {
    sourceIterator = iter;
    initVectors();
    ASBase::init( getFileType() );
    g_preprocessorCppExternCBrace = 0;
    initContainer( waitingBeautifierStack, new vector<ASBeautifier*> );
    initContainer( activeBeautifierStack, new vector<ASBeautifier*> );
    initContainer( waitingBeautifierStackLengthStack, new vector<int> );
    initContainer( activeBeautifierStackLengthStack, new vector<int> );
    initContainer( headerStack, new vector<const string*> );
    initTempStacksContainer( tempStacks, new vector<vector<const string*>*> );
    tempStacks->emplace_back( new vector<const string*> );
    initContainer( squareBracketDepthStack, new vector<int> );
    initContainer( blockStatementStack, new vector<bool> );
    initContainer( parenStatementStack, new vector<bool> );
    initContainer( braceBlockStateStack, new vector<bool> );
    braceBlockStateStack->push_back( true );
    initContainer( continuationIndentStack, new vector<int> );
    initContainer( continuationIndentStackSizeStack, new vector<int> );
    continuationIndentStackSizeStack->emplace_back( 0 );
    initContainer( parenIndentStack, new vector<int> );
    initContainer( preprocIndentStack, new vector<pair<int, int> > );
    previousLastLineHeader = nullptr;
    currentHeader = nullptr;
    isInQuote = false;
    isInVerbatimQuote = false;
    haveLineContinuationChar = false;
    isInAsm = false;
    isInAsmOneLine = false;
    isInAsmBlock = false;
    isInComment = false;
    isInPreprocessorComment = false;
    isInRunInComment = false;
    isContinuation = false;
    isInCase = false;
    isInQuestion = false;
    isIndentModeOff = false;
    isInClassHeader = false;
    isInClassHeaderTab = false;
    isInClassInitializer = false;
    isInClass = false;
    isInObjCMethodDefinition = false;
    isInObjCMethodCall = false;
    isInObjCMethodCallFirst = false;
    isImmediatelyPostObjCMethodDefinition = false;
    isImmediatelyPostObjCMethodCall = false;
    isInIndentablePreprocBlock = false;
    isInObjCInterface = false;
    isInEnum = false;
    isInEnumTypeID = false;
    isInLet = false;
    isInHeader = false;
    isInTemplate = false;
    isInConditional = false;
    indentCount = 0;
    spaceIndentCount = 0;
    spaceIndentObjCMethodAlignment = 0;
    bracePosObjCMethodAlignment = 0;
    colonIndentObjCMethodAlignment = 0;
    lineOpeningBlocksNum = 0;
    lineClosingBlocksNum = 0;
    templateDepth = 0;
    squareBracketCount = 0;
    parenDepth = 0;
    blockTabCount = 0;
    prevFinalLineSpaceIndentCount = 0;
    prevFinalLineIndentCount = 0;
    defineIndentCount = 0;
    preprocBlockIndent = 0;
    prevNonSpaceCh = '{';
    currentNonSpaceCh = '{';
    prevNonLegalCh = '{';
    currentNonLegalCh = '{';
    quoteChar = ' ';
    probationHeader = nullptr;
    lastLineHeader = nullptr;
    backslashEndsPrevLine = false;
    lineOpensWithLineComment = false;
    lineOpensWithComment = false;
    lineStartsInComment = false;
    isInDefine = false;
    isInDefineDefinition = false;
    lineCommentNoBeautify = false;
    isElseHeaderIndent = false;
    isCaseHeaderCommentIndent = false;
    blockCommentNoIndent = false;
    blockCommentNoBeautify = false;
    previousLineProbationTab = false;
    lineBeginsWithOpenBrace = false;
    lineBeginsWithCloseBrace = false;
    lineBeginsWithComma = false;
    lineIsCommentOnly = false;
    lineIsLineCommentOnly = false;
    shouldIndentBracedLine = true;
    isInSwitch = false;
    foundPreCommandHeader = false;
    foundPreCommandMacro = false;
    isNonInStatementArray = false;
    isSharpAccessor = false;
    isSharpDelegate = false;
    isInExternC = false;
    isInBeautifySQL = false;
    isInIndentableStruct = false;
    isInIndentablePreproc = false;
    inLineNumber = 0;
    runInIndentContinuation = 0;
    nonInStatementBrace = 0;
    objCColonAlignSubsequent = 0;
  }

  void ASBeautifier::initVectors() {
    if( fileType == beautifierFileType ) {
      return;
    }
    beautifierFileType = fileType;
    headers->clear();
    nonParenHeaders->clear();
    assignmentOperators->clear();
    nonAssignmentOperators->clear();
    preBlockStatements->clear();
    preCommandHeaders->clear();
    indentableHeaders->clear();
    ASResource::buildHeaders( headers, fileType, true );
    ASResource::buildNonParenHeaders( nonParenHeaders, fileType, true );
    ASResource::buildAssignmentOperators( assignmentOperators );
    ASResource::buildNonAssignmentOperators( nonAssignmentOperators );
    ASResource::buildPreBlockStatements( preBlockStatements, fileType );
    ASResource::buildPreCommandHeaders( preCommandHeaders, fileType );
    ASResource::buildIndentableHeaders( indentableHeaders );
  }

  void ASBeautifier::setCStyle() {
    fileType = C_TYPE;
  }

  void ASBeautifier::setJavaStyle() {
    fileType = JAVA_TYPE;
  }

  void ASBeautifier::setSharpStyle() {
    fileType = SHARP_TYPE;
  }

  void ASBeautifier::setModeManuallySet( bool state ) {
    isModeManuallySet = state;
  }

  void ASBeautifier::setDefaultTabLength() {
    tabLength = indentLength;
  }

  void ASBeautifier::setForceTabXIndentation( int length ) {
    indentString = "\t";
    tabLength = length;
    shouldForceTabIndentation = true;
  }

  void ASBeautifier::setTabIndentation( int length, bool forceTabs ) {
    indentString = "\t";
    indentLength = length;
    shouldForceTabIndentation = forceTabs;
  }

  void ASBeautifier::setSpaceIndentation( int length ) {
    indentString = string( length, ' ' );
    indentLength = length;
  }

  void ASBeautifier::setContinuationIndentation( int indent ) {
    continuationIndent = indent;
  }

  void ASBeautifier::setMaxContinuationIndentLength( int max ) {
    maxContinuationIndent = max;
  }

  void ASBeautifier::setMaxInStatementIndentLength( int max ) {
    setMaxContinuationIndentLength( max );
  }

  void ASBeautifier::setMinConditionalIndentOption( int min ) {
    minConditionalOption = min;
  }

  void ASBeautifier::setMinConditionalIndentLength() {
    if( minConditionalOption == MINCOND_ZERO ) {
      minConditionalIndent = 0;
    } else if( minConditionalOption == MINCOND_ONE ) {
      minConditionalIndent = indentLength;
    } else if( minConditionalOption == MINCOND_ONEHALF ) {
      minConditionalIndent = indentLength / 2;
    } else
    { minConditionalIndent = indentLength * 2; }
  }

  void ASBeautifier::setBraceIndent( bool state ) {
    braceIndent = state;
  }

  void ASBeautifier::setBraceIndentVtk( bool state ) {
    setBraceIndent( state );
    braceIndentVtk = state;
  }

  void ASBeautifier::setBlockIndent( bool state ) {
    blockIndent = state;
  }

  void ASBeautifier::setClassIndent( bool state ) {
    classIndent = state;
  }

  void ASBeautifier::setModifierIndent( bool state ) {
    modifierIndent = state;
  }

  void ASBeautifier::setSwitchIndent( bool state ) {
    switchIndent = state;
  }

  void ASBeautifier::setCaseIndent( bool state ) {
    caseIndent = state;
  }

  void ASBeautifier::setNamespaceIndent( bool state ) {
    namespaceIndent = state;
  }

  void ASBeautifier::setAfterParenIndent( bool state ) {
    shouldIndentAfterParen = state;
  }

  void ASBeautifier::setLabelIndent( bool state ) {
    labelIndent = state;
  }

  void ASBeautifier::setPreprocDefineIndent( bool state ) {
    shouldIndentPreprocDefine = state;
  }

  void ASBeautifier::setPreprocConditionalIndent( bool state ) {
    shouldIndentPreprocConditional = state;
  }

  void ASBeautifier::setEmptyLineFill( bool state ) {
    emptyLineFill = state;
  }

  void ASBeautifier::setAlignMethodColon( bool state ) {
    shouldAlignMethodColon = state;
  }

  int ASBeautifier::getFileType() const {
    return fileType;
  }

  int ASBeautifier::getIndentLength() const {
    return indentLength;
  }

  string ASBeautifier::getIndentString() const {
    return indentString;
  }

  bool ASBeautifier::getModeManuallySet() const {
    return isModeManuallySet;
  }

  bool ASBeautifier::getForceTabIndentation() const {
    return shouldForceTabIndentation;
  }

  bool ASBeautifier::getAlignMethodColon() const {
    return shouldAlignMethodColon;
  }

  bool ASBeautifier::getBlockIndent() const {
    return blockIndent;
  }

  bool ASBeautifier::getBraceIndent() const {
    return braceIndent;
  }

  bool ASBeautifier::getNamespaceIndent() const {
    return namespaceIndent;
  }

  bool ASBeautifier::getClassIndent() const {
    return classIndent;
  }

  bool ASBeautifier::getModifierIndent() const {
    return modifierIndent;
  }

  bool ASBeautifier::getSwitchIndent() const {
    return switchIndent;
  }

  bool ASBeautifier::getCaseIndent() const {
    return caseIndent;
  }

  bool ASBeautifier::getEmptyLineFill() const {
    return emptyLineFill;
  }

  bool ASBeautifier::getPreprocDefineIndent() const {
    return shouldIndentPreprocDefine;
  }

  int ASBeautifier::getTabLength() const {
    return tabLength;
  }

  string ASBeautifier::beautify( const string& originalLine ) {
    string line;
    bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
    currentHeader = nullptr;
    lastLineHeader = nullptr;
    blockCommentNoBeautify = blockCommentNoIndent;
    isInClass = false;
    isInSwitch = false;
    lineBeginsWithOpenBrace = false;
    lineBeginsWithCloseBrace = false;
    lineBeginsWithComma = false;
    lineIsCommentOnly = false;
    lineIsLineCommentOnly = false;
    shouldIndentBracedLine = true;
    isInAsmOneLine = false;
    lineOpensWithLineComment = false;
    lineOpensWithComment = false;
    lineStartsInComment = isInComment;
    previousLineProbationTab = false;
    lineOpeningBlocksNum = 0;
    lineClosingBlocksNum = 0;
    if( isImmediatelyPostObjCMethodDefinition ) {
      clearObjCMethodDefinitionAlignment();
    }
    if( isImmediatelyPostObjCMethodCall ) {
      isImmediatelyPostObjCMethodCall = false;
      isInObjCMethodCall = false;
      objCColonAlignSubsequent = 0;
    }
    if( isInQuoteContinuation ) {
      if( !( originalLine.length() == 1 && originalLine[0] == ' ' ) ) {
        line = originalLine;
      }
    } else if( isInComment || isInBeautifySQL ) {
      line = originalLine;
      size_t trimEnd = line.find_last_not_of( " \t" );
      if( trimEnd == string::npos ) {
        trimEnd = 0;
      } else
      { trimEnd++; }
      if( trimEnd < line.length() ) {
        line.erase( trimEnd );
      }
      size_t firstChar = line.find_first_not_of( " \t" );
      if( firstChar != string::npos ) {
        if( line[firstChar] == '{' ) {
          lineBeginsWithOpenBrace = true;
        } else if( line[firstChar] == '}' ) {
          lineBeginsWithCloseBrace = true;
        } else if( line[firstChar] == ',' ) {
          lineBeginsWithComma = true;
        }
      }
    } else {
      line = trim( originalLine );
      if( line.length() > 0 ) {
        if( line[0] == '{' ) {
          lineBeginsWithOpenBrace = true;
        } else if( line[0] == '}' ) {
          lineBeginsWithCloseBrace = true;
        } else if( line[0] == ',' ) {
          lineBeginsWithComma = true;
        } else if( line.compare( 0, 2, "//" ) == 0 ) {
          lineIsLineCommentOnly = true;
        } else if( line.compare( 0, 2, "/*" ) == 0 ) {
          if( line.find( "*/", 2 ) != string::npos ) {
            lineIsCommentOnly = true;
          }
        }
      }
      isInRunInComment = false;
      size_t j = line.find_first_not_of( " \t{" );
      if( j != string::npos && line.compare( j, 2, "//" ) == 0 ) {
        lineOpensWithLineComment = true;
      }
      if( j != string::npos && line.compare( j, 2, "/*" ) == 0 ) {
        lineOpensWithComment = true;
        size_t k = line.find_first_not_of( " \t" );
        if( k != string::npos && line.compare( k, 1, "{" ) == 0 ) {
          isInRunInComment = true;
        }
      }
    }
    if( ( lineIsLineCommentOnly || lineIsCommentOnly )
        && line.find( "*INDENT-OFF*", 0 ) != string::npos ) {
      isIndentModeOff = true;
    }
    if( line.length() == 0 ) {
      if( backslashEndsPrevLine ) {
        backslashEndsPrevLine = false;
        if( isInDefineDefinition && !isInDefine ) {
          isInDefineDefinition = false;
          ASBeautifier* defineBeautifier = activeBeautifierStack->back();
          activeBeautifierStack->pop_back();
          delete defineBeautifier;
        }
      }
      if( emptyLineFill && !isInQuoteContinuation ) {
        if( isInIndentablePreprocBlock ) {
          return preLineWS( preprocBlockIndent, 0 );
        }
        if( !headerStack->empty() || isInEnum ) {
          return preLineWS( prevFinalLineIndentCount, prevFinalLineSpaceIndentCount );
        }
      } else
      { return line; }
    }
    if( isInIndentablePreprocBlock
        && line.length() > 0
        && line[0] != '#' ) {
      string indentedLine;
      if( isInClassHeaderTab || isInClassInitializer ) {
        indentedLine = preLineWS( prevFinalLineIndentCount, prevFinalLineSpaceIndentCount ) + line;
        return getIndentedLineReturn( indentedLine, originalLine );
      }
      indentedLine = preLineWS( preprocBlockIndent, 0 ) + line;
      return getIndentedLineReturn( indentedLine, originalLine );
    }
    if( !isInComment
        && !isInQuoteContinuation
        && line.length() > 0
        && ( ( line[0] == '#' && !isIndentedPreprocessor( line, 0 ) )
             || backslashEndsPrevLine ) ) {
      if( line[0] == '#' && !isInDefine ) {
        string preproc = extractPreprocessorStatement( line );
        processPreprocessor( preproc, line );
        if( isInIndentablePreprocBlock || isInIndentablePreproc ) {
          string indentedLine;
          if( ( preproc.length() >= 2 && preproc.substr( 0, 2 ) == "if" ) ) { // #if, #ifdef, #ifndef
            indentedLine = preLineWS( preprocBlockIndent, 0 ) + line;
            preprocBlockIndent += 1;
            isInIndentablePreprocBlock = true;
          } else if( preproc == "else" || preproc == "elif" ) {
            indentedLine = preLineWS( preprocBlockIndent - 1, 0 ) + line;
          } else if( preproc == "endif" ) {
            preprocBlockIndent -= 1;
            indentedLine = preLineWS( preprocBlockIndent, 0 ) + line;
            if( preprocBlockIndent == 0 )
            { isInIndentablePreprocBlock = false; }
          } else
          { indentedLine = preLineWS( preprocBlockIndent, 0 ) + line; }
          return getIndentedLineReturn( indentedLine, originalLine );
        }
        if( shouldIndentPreprocConditional && preproc.length() > 0 ) {
          string indentedLine;
          if( preproc.length() >= 2 && preproc.substr( 0, 2 ) == "if" ) { // #if, #ifdef, #ifndef
            pair<int, int> entry;
            if( !isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty() )
            { entry = activeBeautifierStack->back()->computePreprocessorIndent(); }
            else
            { entry = computePreprocessorIndent(); }
            preprocIndentStack->emplace_back( entry );
            indentedLine = preLineWS( preprocIndentStack->back().first,
                                      preprocIndentStack->back().second ) + line;
            return getIndentedLineReturn( indentedLine, originalLine );
          }
          if( preproc == "else" || preproc == "elif" ) {
            if( !preprocIndentStack->empty() ) {
              indentedLine = preLineWS( preprocIndentStack->back().first,
                                        preprocIndentStack->back().second ) + line;
              return getIndentedLineReturn( indentedLine, originalLine );
            }
          } else if( preproc == "endif" ) {
            if( !preprocIndentStack->empty() ) {
              indentedLine = preLineWS( preprocIndentStack->back().first,
                                        preprocIndentStack->back().second ) + line;
              preprocIndentStack->pop_back();
              return getIndentedLineReturn( indentedLine, originalLine );
            }
          }
        }
      }
      if( line.length() > 0 ) {
        backslashEndsPrevLine = ( line[line.length() - 1] == '\\' );
      }
      if( isInPreprocessorUnterminatedComment( line ) ) {
        backslashEndsPrevLine = true;
      }
      if( !backslashEndsPrevLine && isInDefineDefinition && !isInDefine ) {
        isInDefineDefinition = false;
        ASBeautifier* defineBeautifier = activeBeautifierStack->back();
        activeBeautifierStack->pop_back();
        string indentedLine = defineBeautifier->beautify( line );
        delete defineBeautifier;
        return getIndentedLineReturn( indentedLine, originalLine );
      }
      if( !isInDefine && !isInDefineDefinition ) {
        return originalLine;
      }
    }
    if( !isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty() ) {
      activeBeautifierStack->back()->inLineNumber = inLineNumber;
      activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
      activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
      activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
      activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
      activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent;
      activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent;
      activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
      activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
      activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
      activeBeautifierStack->back()->isInExternC = isInExternC;
      activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
      activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
      activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
      return activeBeautifierStack->back()->beautify( originalLine );
    }
    bool isInExtraHeaderIndent = false;
    if( !headerStack->empty() && lineBeginsWithOpenBrace && ( headerStack->back() != &AS_OPEN_BRACE
        || probationHeader != nullptr ) ) {
      isInExtraHeaderIndent = true;
    }
    size_t iPrelim = headerStack->size();
    computePreliminaryIndentation();
    parseCurrentLine( line );
    adjustParsedLineIndentation( iPrelim, isInExtraHeaderIndent );
    if( isInObjCMethodDefinition ) {
      adjustObjCMethodDefinitionIndentation( line );
    }
    if( isInObjCMethodCall ) {
      adjustObjCMethodCallIndentation( line );
    }
    if( isInDefine ) {
      if( line.length() > 0 && line[0] == '#' ) {
        string preproc = trim( line.substr( 1 ) );
        if( preproc.compare( 0, 6, "define" ) == 0 ) {
          if( !continuationIndentStack->empty()
              && continuationIndentStack->back() > 0 ) {
            defineIndentCount = indentCount;
          } else {
            defineIndentCount = indentCount - 1;
            --indentCount;
          }
        }
      }
      indentCount -= defineIndentCount;
    }
    if( indentCount < 0 ) {
      indentCount = 0;
    }
    if( lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation ) {
      indentCount = spaceIndentCount = 0;
    }
    string indentedLine = preLineWS( indentCount, spaceIndentCount ) + line;
    indentedLine = getIndentedLineReturn( indentedLine, originalLine );
    prevFinalLineSpaceIndentCount = spaceIndentCount;
    prevFinalLineIndentCount = indentCount;
    if( lastLineHeader != nullptr ) {
      previousLastLineHeader = lastLineHeader;
    }
    if( ( lineIsLineCommentOnly || lineIsCommentOnly )
        && line.find( "*INDENT-ON*", 0 ) != string::npos ) {
      isIndentModeOff = false;
    }
    return indentedLine;
  }

  const string& ASBeautifier::getIndentedLineReturn( const string& newLine, const string& originalLine ) const {
    if( isIndentModeOff ) {
      return originalLine;
    }
    return newLine;
  }

  string ASBeautifier::preLineWS( int lineIndentCount, int lineSpaceIndentCount ) const {
    if( shouldForceTabIndentation ) {
      if( tabLength != indentLength ) {
        int indentCountOrig = lineIndentCount;
        int spaceIndentCountOrig = lineSpaceIndentCount;
        lineIndentCount = ( ( indentCountOrig * indentLength ) + spaceIndentCountOrig ) / tabLength;
        lineSpaceIndentCount = ( ( indentCountOrig * indentLength ) + spaceIndentCountOrig ) % tabLength;
      } else {
        lineIndentCount += lineSpaceIndentCount / indentLength;
        lineSpaceIndentCount = lineSpaceIndentCount % indentLength;
      }
    }
    string ws;
    for( int i = 0; i < lineIndentCount; i++ ) {
      ws += indentString;
    }
    while( ( lineSpaceIndentCount-- ) > 0 ) {
      ws += string( " " );
    }
    return ws;
  }

  void ASBeautifier::registerContinuationIndent( const string& line, int i, int spaceIndentCount_,
      int tabIncrementIn, int minIndent, bool updateParenStack ) {
    int remainingCharNum = line.length() - i;
    int nextNonWSChar = getNextProgramCharDistance( line, i );
    if( nextNonWSChar == remainingCharNum || shouldIndentAfterParen ) {
      int previousIndent = spaceIndentCount_;
      if( !continuationIndentStack->empty() ) {
        previousIndent = continuationIndentStack->back();
      }
      int currIndent = continuationIndent * indentLength + previousIndent;
      if( currIndent > maxContinuationIndent && line[i] != '{' ) {
        currIndent = indentLength * 2 + spaceIndentCount_;
      }
      continuationIndentStack->emplace_back( currIndent );
      if( updateParenStack ) {
        parenIndentStack->emplace_back( previousIndent );
      }
      return;
    }
    if( updateParenStack ) {
      parenIndentStack->emplace_back( i + spaceIndentCount_ - runInIndentContinuation );
    }
    int tabIncrement = tabIncrementIn;
    for( int j = i + 1; j < ( i + nextNonWSChar ); j++ ) {
      if( line[j] == '\t' ) {
        tabIncrement += convertTabToSpaces( j, tabIncrement );
      }
    }
    int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
    if( i > 0 && line[0] == '{' ) {
      continuationIndentCount -= indentLength;
    }
    if( continuationIndentCount < minIndent ) {
      continuationIndentCount = minIndent + spaceIndentCount_;
    }
    if( continuationIndentCount > maxContinuationIndent
        && !( prevNonLegalCh == '=' && currentNonLegalCh == '{' ) ) {
      continuationIndentCount = indentLength * 2 + spaceIndentCount_;
    }
    if( !continuationIndentStack->empty()
        && continuationIndentCount < continuationIndentStack->back() ) {
      continuationIndentCount = continuationIndentStack->back();
    }
    if( ( isNonInStatementArray && line[i] == '{' )
        && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back() ) {
      continuationIndentCount = 0;
    }
    continuationIndentStack->emplace_back( continuationIndentCount );
  }

  void ASBeautifier::registerContinuationIndentColon( const string& line, int i, int tabIncrementIn ) {
    assert( line[i] == ':' );
    assert( isInClassInitializer || isInClassHeaderTab );
    size_t firstChar = line.find_first_not_of( " \t" );
    if( firstChar == ( size_t ) i ) {
      size_t firstWord = line.find_first_not_of( " \t", firstChar + 1 );
      if( firstChar != string::npos ) {
        int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
        continuationIndentStack->emplace_back( continuationIndentCount );
        isContinuation = true;
      }
    }
  }

  pair<int, int> ASBeautifier::computePreprocessorIndent() {
    computePreliminaryIndentation();
    pair<int, int> entry( indentCount, spaceIndentCount );
    if( !headerStack->empty() && entry.first > 0 && ( headerStack->back() == &AS_IF
        || headerStack->back() == &AS_ELSE || headerStack->back() == &AS_FOR
        || headerStack->back() == &AS_WHILE ) ) {
      --entry.first;
    }
    return entry;
  }

  int ASBeautifier::getNextProgramCharDistance( const string& line, int i ) const {
    bool inComment = false;
    int  remainingCharNum = line.length() - i;
    int  charDistance;
    char ch;
    for( charDistance = 1; charDistance < remainingCharNum; charDistance++ ) {
      ch = line[i + charDistance];
      if( inComment ) {
        if( line.compare( i + charDistance, 2, "*/" ) == 0 ) {
          charDistance++;
          inComment = false;
        }
        continue;
      } else if( isWhiteSpace( ch ) ) {
        continue;
      } else if( ch == '/' ) {
        if( line.compare( i + charDistance, 2, "//" ) == 0 ) {
          return remainingCharNum;
        }
        if( line.compare( i + charDistance, 2, "/*" ) == 0 ) {
          charDistance++;
          inComment = true;
        }
      } else
      { return charDistance; }
    }
    return charDistance;
  }

  int ASBeautifier::indexOf( const vector<const string*>& container, const string* element ) const {
    vector<const string*>::const_iterator where;
    where = find( container.begin(), container.end(), element );
    if( where == container.end() ) {
      return -1;
    }
    return ( int )( where - container.begin() );
  }

  int ASBeautifier::convertTabToSpaces( int i, int tabIncrementIn ) const {
    int tabToSpacesAdjustment = indentLength - 1 - ( ( tabIncrementIn + i ) % indentLength );
    return tabToSpacesAdjustment;
  }

  string ASBeautifier::trim( const string& str ) const {
    int start = 0;
    int end = str.length() - 1;
    while( start < end && isWhiteSpace( str[start] ) ) {
      start++;
    }
    while( start <= end && isWhiteSpace( str[end] ) ) {
      end--;
    }
    if( end > -1 && str[end] == '\\' ) {
      end = str.length() - 1;
    }
    string returnStr( str, start, end + 1 - start );
    return returnStr;
  }

  string ASBeautifier::rtrim( const string& str ) const {
    size_t len = str.length();
    size_t end = str.find_last_not_of( " \t" );
    if( end == string::npos
        || end == len - 1 ) {
      return str;
    }
    string returnStr( str, 0, end + 1 );
    return returnStr;
  }

  vector<vector<const string*>*>* ASBeautifier::copyTempStacks( const ASBeautifier& other ) const {
    vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>;
    vector<vector<const string*>*>::iterator iter;
    for( iter = other.tempStacks->begin();
         iter != other.tempStacks->end();
         ++iter ) {
      vector<const string*>* newVec = new vector<const string*>;
      *newVec = **iter;
      tempStacksNew->emplace_back( newVec );
    }
    return tempStacksNew;
  }

  void ASBeautifier::deleteBeautifierVectors() {
    beautifierFileType = 9;
    delete headers;
    delete nonParenHeaders;
    delete preBlockStatements;
    delete preCommandHeaders;
    delete assignmentOperators;
    delete nonAssignmentOperators;
    delete indentableHeaders;
  }

  template<typename T>
  void ASBeautifier::deleteContainer( T& container ) {
    if( container != nullptr ) {
      container->clear();
      delete( container );
      container = nullptr;
    }
  }

  void ASBeautifier::deleteBeautifierContainer( vector<ASBeautifier*>*& container ) {
    if( container != nullptr ) {
      vector<ASBeautifier*>::iterator iter = container->begin();
      while( iter < container->end() ) {
        delete *iter;
        ++iter;
      }
      container->clear();
      delete( container );
      container = nullptr;
    }
  }

  void ASBeautifier::deleteTempStacksContainer( vector<vector<const string*>*>*& container ) {
    if( container != nullptr ) {
      vector<vector<const string*>*>::iterator iter = container->begin();
      while( iter < container->end() ) {
        delete *iter;
        ++iter;
      }
      container->clear();
      delete( container );
      container = nullptr;
    }
  }

  template<typename T>
  void ASBeautifier::initContainer( T& container, T value ) {
    if( container != nullptr ) {
      deleteContainer( container );
    }
    container = value;
  }

  void ASBeautifier::initTempStacksContainer( vector<vector<const string*>*>*& container,
      vector<vector<const string*>*>* value ) {
    if( container != nullptr ) {
      deleteTempStacksContainer( container );
    }
    container = value;
  }

  bool ASBeautifier::statementEndsWithComma( const string& line, int index ) const {
    assert( line[index] == '=' );
    bool isInComment_ = false;
    bool isInQuote_ = false;
    int parenCount = 0;
    size_t lineLength = line.length();
    size_t i = 0;
    char quoteChar_ = ' ';
    for( i = index + 1; i < lineLength; ++i ) {
      char ch = line[i];
      if( isInComment_ ) {
        if( line.compare( i, 2, "*/" ) == 0 ) {
          isInComment_ = false;
          ++i;
        }
        continue;
      }
      if( ch == '\\' ) {
        ++i;
        continue;
      }
      if( isInQuote_ ) {
        if( ch == quoteChar_ ) {
          isInQuote_ = false;
        }
        continue;
      }
      if( ch == '"'
          || ( ch == '\'' && !isDigitSeparator( line, i ) ) ) {
        isInQuote_ = true;
        quoteChar_ = ch;
        continue;
      }
      if( line.compare( i, 2, "//" ) == 0 ) {
        break;
      }
      if( line.compare( i, 2, "/*" ) == 0 ) {
        if( isLineEndComment( line, i ) ) {
          break;
        } else {
          isInComment_ = true;
          ++i;
          continue;
        }
      }
      if( ch == '(' ) {
        parenCount++;
      }
      if( ch == ')' ) {
        parenCount--;
      }
    }
    if( isInComment_
        || isInQuote_
        || parenCount > 0 ) {
      return false;
    }
    size_t lastChar = line.find_last_not_of( " \t", i - 1 );
    if( lastChar == string::npos || line[lastChar] != ',' ) {
      return false;
    }
    return true;
  }

  bool ASBeautifier::isLineEndComment( const string& line, int startPos ) const {
    assert( line.compare( startPos, 2, "/*" ) == 0 );
    size_t endNum = line.find( "*/", startPos + 2 );
    if( endNum != string::npos ) {
      size_t nextChar = line.find_first_not_of( " \t", endNum + 2 );
      if( nextChar == string::npos ) {
        return true;
      }
    }
    return false;
  }

  int ASBeautifier::getContinuationIndentAssign( const string& line, size_t currPos ) const {
    assert( line[currPos] == '=' );
    if( currPos == 0 ) {
      return 0;
    }
    size_t end = line.find_last_not_of( " \t", currPos - 1 );
    if( end == string::npos || !isLegalNameChar( line[end] ) ) {
      return 0;
    }
    int start;
    for( start = end; start > -1; start-- ) {
      if( !isLegalNameChar( line[start] ) || line[start] == '.' ) {
        break;
      }
    }
    start++;
    return start;
  }

  int ASBeautifier::getContinuationIndentComma( const string& line, size_t currPos ) const {
    assert( line[currPos] == ',' );
    size_t indent = line.find_first_not_of( " \t" );
    if( indent == string::npos || !isLegalNameChar( line[indent] ) ) {
      return 0;
    }
    for( ; indent < currPos; indent++ ) {
      if( !isLegalNameChar( line[indent] ) ) {
        break;
      }
    }
    indent++;
    if( indent >= currPos || indent < 4 ) {
      return 0;
    }
    indent = line.find_first_not_of( " \t", indent );
    if( indent == string::npos || indent >= currPos ) {
      return 0;
    }
    return indent;
  }

  string ASBeautifier::getNextWord( const string& line, size_t currPos ) const {
    size_t lineLength = line.length();
    if( currPos == lineLength - 1 ) {
      return string();
    }
    size_t start = line.find_first_not_of( " \t", currPos + 1 );
    if( start == string::npos || !isLegalNameChar( line[start] ) ) {
      return string();
    }
    size_t end;
    for( end = start + 1; end <= lineLength; end++ ) {
      if( !isLegalNameChar( line[end] ) || line[end] == '.' ) {
        break;
      }
    }
    return line.substr( start, end - start );
  }

  bool ASBeautifier::isIndentedPreprocessor( const string& line, size_t currPos ) const {
    assert( line[0] == '#' );
    string nextWord = getNextWord( line, currPos );
    if( nextWord == "region" || nextWord == "endregion" ) {
      return true;
    }
    if( nextWord == "pragma" ) {
      size_t start = line.find( "pragma" );
      if( start == string::npos || !isLegalNameChar( line[start] ) ) {
        return false;
      }
      for( ; start < line.length(); start++ ) {
        if( !isLegalNameChar( line[start] ) ) {
          break;
        }
      }
      start++;
      if( start >= line.length() ) {
        return false;
      }
      start = line.find_first_not_of( " \t", start );
      if( start == string::npos ) {
        return false;
      }
      size_t end;
      for( end = start; end < line.length(); end++ ) {
        if( !isLegalNameChar( line[end] ) ) {
          break;
        }
      }
      string word = line.substr( start, end - start );
      if( word == "omp" || word == "region" || word == "endregion" ) {
        return true;
      }
    }
    return false;
  }

  bool ASBeautifier::isPreprocessorConditionalCplusplus( const string& line ) const {
    string preproc = trim( line.substr( 1 ) );
    if( preproc.compare( 0, 5, "ifdef" ) == 0 && getNextWord( preproc, 4 ) == "__cplusplus" ) {
      return true;
    }
    if( preproc.compare( 0, 2, "if" ) == 0 ) {
      size_t charNum = 2;
      charNum = preproc.find_first_not_of( " \t", charNum );
      if( charNum != string::npos && preproc.compare( charNum, 7, "defined" ) == 0 ) {
        charNum += 7;
        charNum = preproc.find_first_not_of( " \t", charNum );
        if( preproc.compare( charNum, 1, "(" ) == 0 ) {
          ++charNum;
          charNum = preproc.find_first_not_of( " \t", charNum );
          if( preproc.compare( charNum, 11, "__cplusplus" ) == 0 ) {
            return true;
          }
        }
      }
    }
    return false;
  }

  bool ASBeautifier::isInPreprocessorUnterminatedComment( const string& line ) {
    if( !isInPreprocessorComment ) {
      size_t startPos = line.find( "/*" );
      if( startPos == string::npos ) {
        return false;
      }
    }
    size_t endNum = line.find( "*/" );
    if( endNum != string::npos ) {
      isInPreprocessorComment = false;
      return false;
    }
    isInPreprocessorComment = true;
    return true;
  }

  void ASBeautifier::popLastContinuationIndent() {
    assert( !continuationIndentStackSizeStack->empty() );
    int previousIndentStackSize = continuationIndentStackSizeStack->back();
    if( continuationIndentStackSizeStack->size() > 1 ) {
      continuationIndentStackSizeStack->pop_back();
    }
    while( previousIndentStackSize < ( int ) continuationIndentStack->size() ) {
      continuationIndentStack->pop_back();
    }
  }

  int ASBeautifier::getBeautifierFileType() const
  { return beautifierFileType; }

  void ASBeautifier::processPreprocessor( const string& preproc, const string& line ) {
    if( shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\' ) {
      if( !isInDefineDefinition ) {
        isInDefineDefinition = true;
        ASBeautifier* defineBeautifier = new ASBeautifier( *this );
        activeBeautifierStack->emplace_back( defineBeautifier );
      } else
      { isInDefine = true; }
    } else if( preproc.length() >= 2 && preproc.substr( 0, 2 ) == "if" ) {
      if( isPreprocessorConditionalCplusplus( line ) && !g_preprocessorCppExternCBrace ) {
        g_preprocessorCppExternCBrace = 1;
      }
      waitingBeautifierStackLengthStack->push_back( waitingBeautifierStack->size() );
      activeBeautifierStackLengthStack->push_back( activeBeautifierStack->size() );
      if( activeBeautifierStackLengthStack->back() == 0 ) {
        waitingBeautifierStack->emplace_back( new ASBeautifier( *this ) );
      } else
      { waitingBeautifierStack->emplace_back( new ASBeautifier( *activeBeautifierStack->back() ) ); }
    } else if( preproc == "else" ) {
      if( ( waitingBeautifierStack != nullptr ) && !waitingBeautifierStack->empty() ) {
        activeBeautifierStack->emplace_back( waitingBeautifierStack->back() );
        waitingBeautifierStack->pop_back();
      }
    } else if( preproc == "elif" ) {
      if( ( waitingBeautifierStack != nullptr ) && !waitingBeautifierStack->empty() ) {
        activeBeautifierStack->emplace_back( new ASBeautifier( *( waitingBeautifierStack->back() ) ) );
      }
    } else if( preproc == "endif" ) {
      int stackLength = 0;
      ASBeautifier* beautifier = nullptr;
      if( waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty() ) {
        stackLength = waitingBeautifierStackLengthStack->back();
        waitingBeautifierStackLengthStack->pop_back();
        while( ( int ) waitingBeautifierStack->size() > stackLength ) {
          beautifier = waitingBeautifierStack->back();
          waitingBeautifierStack->pop_back();
          delete beautifier;
        }
      }
      if( !activeBeautifierStackLengthStack->empty() ) {
        stackLength = activeBeautifierStackLengthStack->back();
        activeBeautifierStackLengthStack->pop_back();
        while( ( int ) activeBeautifierStack->size() > stackLength ) {
          beautifier = activeBeautifierStack->back();
          activeBeautifierStack->pop_back();
          delete beautifier;
        }
      }
    }
  }

  void ASBeautifier::computePreliminaryIndentation() {
    indentCount = 0;
    spaceIndentCount = 0;
    isInClassHeaderTab = false;
    if( isInObjCMethodDefinition && !continuationIndentStack->empty() ) {
      spaceIndentObjCMethodAlignment = continuationIndentStack->back();
    }
    if( !continuationIndentStack->empty() ) {
      spaceIndentCount = continuationIndentStack->back();
    }
    for( size_t i = 0; i < headerStack->size(); i++ ) {
      isInClass = false;
      if( blockIndent ) {
        if( !( ( *headerStack )[i] == &AS_NAMESPACE
               || ( *headerStack )[i] == &AS_MODULE
               || ( *headerStack )[i] == &AS_CLASS
               || ( *headerStack )[i] == &AS_STRUCT
               || ( *headerStack )[i] == &AS_UNION
               || ( *headerStack )[i] == &AS_INTERFACE
               || ( *headerStack )[i] == &AS_THROWS
               || ( *headerStack )[i] == &AS_STATIC ) ) {
          ++indentCount;
        }
      } else if( !( i > 0 && ( *headerStack )[i - 1] != &AS_OPEN_BRACE
                    && ( *headerStack )[i] == &AS_OPEN_BRACE ) ) {
        ++indentCount;
      }
      if( !isJavaStyle() && !namespaceIndent && i > 0
          && ( ( *headerStack )[i - 1] == &AS_NAMESPACE
               || ( *headerStack )[i - 1] == &AS_MODULE )
          && ( *headerStack )[i] == &AS_OPEN_BRACE ) {
        --indentCount;
      }
      if( isCStyle() && i >= 1
          && ( *headerStack )[i - 1] == &AS_CLASS
          && ( *headerStack )[i] == &AS_OPEN_BRACE ) {
        if( classIndent ) {
          ++indentCount;
        }
        isInClass = true;
      } else if( switchIndent && i > 1
                 && ( *headerStack )[i - 1] == &AS_SWITCH
                 && ( *headerStack )[i] == &AS_OPEN_BRACE ) {
        ++indentCount;
        isInSwitch = true;
      }
    }
    if( isInClassHeader ) {
      if( !isJavaStyle() ) {
        isInClassHeaderTab = true;
      }
      if( lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment ) {
        if( !lineBeginsWithOpenBrace ) {
          --indentCount;
        }
        if( !continuationIndentStack->empty() ) {
          spaceIndentCount -= continuationIndentStack->back();
        }
      } else if( blockIndent ) {
        if( !lineBeginsWithOpenBrace ) {
          ++indentCount;
        }
      }
    }
    if( isInClassInitializer || isInEnumTypeID ) {
      indentCount += classInitializerIndents;
    }
    if( isInEnum && lineBeginsWithComma && !continuationIndentStack->empty() ) {
      continuationIndentStack->pop_back();
      isContinuation = false;
      spaceIndentCount = 0;
    }
    if( isInObjCInterface ) {
      ++indentCount;
    }
    if( !lineStartsInComment
        && isCStyle()
        && isInClass
        && classIndent
        && headerStack->size() >= 2
        && ( *headerStack )[headerStack->size() - 2] == &AS_CLASS
        && ( *headerStack )[headerStack->size() - 1] == &AS_OPEN_BRACE
        && lineBeginsWithCloseBrace
        && braceBlockStateStack->back() ) {
      --indentCount;
    } else if( !lineStartsInComment
               && isInSwitch
               && switchIndent
               && headerStack->size() >= 2
               && ( *headerStack )[headerStack->size() - 2] == &AS_SWITCH
               && ( *headerStack )[headerStack->size() - 1] == &AS_OPEN_BRACE
               && lineBeginsWithCloseBrace ) {
      --indentCount;
    }
    if( isInClass
        && classIndent
        && isInRunInComment
        && !lineOpensWithComment
        && headerStack->size() > 1
        && ( *headerStack )[headerStack->size() - 2] == &AS_CLASS ) {
      --indentCount;
    }
    if( isInConditional ) {
      --indentCount;
    }
    if( g_preprocessorCppExternCBrace >= 4 ) {
      --indentCount;
    }
  }

  void ASBeautifier::adjustParsedLineIndentation( size_t iPrelim, bool isInExtraHeaderIndent ) {
    if( lineStartsInComment ) {
      return;
    }
    if( !blockIndent
        && lineBeginsWithOpenBrace
        && headerStack->size() < iPrelim
        && isInExtraHeaderIndent
        && ( lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum )
        && shouldIndentBracedLine ) {
      --indentCount;
    } else if( !blockIndent
               && lineBeginsWithOpenBrace
               && !( lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum )
               && ( headerStack->size() > 1 && ( *headerStack )[headerStack->size() - 2] != &AS_OPEN_BRACE )
               && shouldIndentBracedLine ) {
      --indentCount;
    } else if( headerStack->size() > iPrelim + 1
               && !blockIndent
               && lineBeginsWithOpenBrace
               && !( lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum )
               && ( headerStack->size() > 2 && ( *headerStack )[headerStack->size() - 3] != &AS_OPEN_BRACE )
               && shouldIndentBracedLine ) {
      --indentCount;
    } else if( lineBeginsWithCloseBrace
               && shouldIndentBracedLine ) {
      --indentCount;
    } else if( lineOpeningBlocksNum > 0
               && lineOpeningBlocksNum == lineClosingBlocksNum
               && previousLineProbationTab ) {
      --indentCount;
    }
    if( indentCount < 0 ) {
      indentCount = 0;
    }
    if( !lineStartsInComment
        && braceIndent
        && shouldIndentBracedLine
        && ( lineBeginsWithOpenBrace || lineBeginsWithCloseBrace ) ) {
      if( !braceIndentVtk ) {
        ++indentCount;
      } else {
        bool haveUnindentedBrace = false;
        for( size_t i = 0; i < headerStack->size(); i++ ) {
          if( ( ( *headerStack )[i] == &AS_NAMESPACE
                || ( *headerStack )[i] == &AS_MODULE
                || ( *headerStack )[i] == &AS_CLASS
                || ( *headerStack )[i] == &AS_STRUCT )
              && i + 1 < headerStack->size()
              && ( *headerStack )[i + 1] == &AS_OPEN_BRACE ) {
            i++;
          } else if( lineBeginsWithOpenBrace ) {
            if( i + 1 < headerStack->size()
                && ( *headerStack )[i] == &AS_OPEN_BRACE )
            { haveUnindentedBrace = true; }
          } else if( ( *headerStack )[i] == &AS_OPEN_BRACE ) {
            haveUnindentedBrace = true;
          }
        }
        if( haveUnindentedBrace ) {
          ++indentCount;
        }
      }
    }
  }

  int ASBeautifier::adjustIndentCountForBreakElseIfComments() const {
    assert( isElseHeaderIndent && !tempStacks->empty() );
    int indentCountIncrement = 0;
    vector<const string*>* lastTempStack = tempStacks->back();
    if( lastTempStack != nullptr ) {
      for( size_t i = 0; i < lastTempStack->size(); i++ ) {
        if( *lastTempStack->at( i ) == AS_ELSE ) {
          indentCountIncrement++;
        }
      }
    }
    return indentCountIncrement;
  }

  string ASBeautifier::extractPreprocessorStatement( const string& line ) const {
    string preproc;
    size_t start = line.find_first_not_of( "#/ \t" );
    if( start == string::npos ) {
      return preproc;
    }
    size_t end = line.find_first_of( "/ \t", start );
    if( end == string::npos ) {
      end = line.length();
    }
    preproc = line.substr( start, end - start );
    return preproc;
  }

  void ASBeautifier::adjustObjCMethodDefinitionIndentation( const string& line_ ) {
    if( line_.length() > 0
        && ( line_[0] == '-' || line_[0] == '+' ) ) {
      if( shouldAlignMethodColon && objCColonAlignSubsequent != -1 ) {
        string convertedLine = getIndentedSpaceEquivalent( line_ );
        colonIndentObjCMethodAlignment = convertedLine.find( ':' );
        int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
        if( objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment ) {
          colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
        }
      } else if( continuationIndentStack->empty()
                 || continuationIndentStack->back() == 0 ) {
        continuationIndentStack->emplace_back( indentLength );
        isContinuation = true;
      }
    } else if( !lineBeginsWithOpenBrace ) {
      if( shouldAlignMethodColon ) {
        spaceIndentCount = computeObjCColonAlignment( line_, colonIndentObjCMethodAlignment );
      } else if( continuationIndentStack->empty() ) {
        spaceIndentCount = spaceIndentObjCMethodAlignment;
      }
    }
  }

  void ASBeautifier::adjustObjCMethodCallIndentation( const string& line_ ) {
    static int keywordIndentObjCMethodAlignment = 0;
    if( shouldAlignMethodColon && objCColonAlignSubsequent != -1 ) {
      if( isInObjCMethodCallFirst ) {
        isInObjCMethodCallFirst = false;
        string convertedLine = getIndentedSpaceEquivalent( line_ );
        bracePosObjCMethodAlignment = convertedLine.find( '[' );
        keywordIndentObjCMethodAlignment =
          getObjCFollowingKeyword( convertedLine, bracePosObjCMethodAlignment );
        colonIndentObjCMethodAlignment = convertedLine.find( ':' );
        if( colonIndentObjCMethodAlignment >= 0 ) {
          int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
          if( objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment ) {
            colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
          }
          if( lineBeginsWithOpenBrace ) {
            colonIndentObjCMethodAlignment -= indentLength;
          }
        }
      } else {
        if( line_.find( ':' ) != string::npos ) {
          if( colonIndentObjCMethodAlignment < 0 ) {
            spaceIndentCount += computeObjCColonAlignment( line_, objCColonAlignSubsequent );
          } else if( objCColonAlignSubsequent > colonIndentObjCMethodAlignment ) {
            spaceIndentCount = computeObjCColonAlignment( line_, objCColonAlignSubsequent );
          } else
          { spaceIndentCount = computeObjCColonAlignment( line_, colonIndentObjCMethodAlignment ); }
        } else {
          if( spaceIndentCount < colonIndentObjCMethodAlignment ) {
            spaceIndentCount += keywordIndentObjCMethodAlignment;
          }
        }
      }
    } else {
      if( isInObjCMethodCallFirst ) {
        isInObjCMethodCallFirst = false;
        string convertedLine = getIndentedSpaceEquivalent( line_ );
        bracePosObjCMethodAlignment = convertedLine.find( '[' );
        keywordIndentObjCMethodAlignment =
          getObjCFollowingKeyword( convertedLine, bracePosObjCMethodAlignment );
      } else {
        if( spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment ) {
          spaceIndentCount += keywordIndentObjCMethodAlignment;
        }
      }
    }
  }

  void ASBeautifier::clearObjCMethodDefinitionAlignment() {
    assert( isImmediatelyPostObjCMethodDefinition );
    spaceIndentCount = 0;
    spaceIndentObjCMethodAlignment = 0;
    colonIndentObjCMethodAlignment = 0;
    isInObjCMethodDefinition = false;
    isImmediatelyPostObjCMethodDefinition = false;
    if( !continuationIndentStack->empty() ) {
      continuationIndentStack->pop_back();
    }
  }

  int ASBeautifier::computeObjCColonAlignment( const string& line, int colonAlignPosition ) const {
    int colonPosition = line.find( ':' );
    if( colonPosition < 0 || colonPosition > colonAlignPosition ) {
      return indentLength;
    }
    return ( colonAlignPosition - colonPosition );
  }

  int ASBeautifier::getObjCFollowingKeyword( const string& line, int bracePos ) const {
    assert( line[bracePos] == '[' );
    size_t firstText = line.find_first_not_of( " \t", bracePos + 1 );
    if( firstText == string::npos ) {
      return -( indentCount * indentLength - 1 );
    }
    size_t searchBeg = firstText;
    size_t objectEnd = 0;
    if( line[searchBeg] == '[' ) {
      objectEnd = line.find( ']', searchBeg + 1 );
      if( objectEnd == string::npos ) {
        return 0;
      }
    } else {
      if( line[searchBeg] == '(' ) {
        searchBeg = line.find( ')', searchBeg + 1 );
        if( searchBeg == string::npos ) {
          return 0;
        }
      }
      objectEnd = line.find_first_of( " \t", searchBeg + 1 );
      if( objectEnd == string::npos ) {
        return 0;
      }
      --objectEnd;
    }
    size_t keyPos = line.find_first_not_of( " \t", objectEnd + 1 );
    if( keyPos == string::npos ) {
      return 0;
    }
    return keyPos - firstText;
  }

  string ASBeautifier::getIndentedSpaceEquivalent( const string& line_ ) const {
    string spaceIndent;
    spaceIndent.append( spaceIndentCount, ' ' );
    string convertedLine = spaceIndent + line_;
    for( size_t i = spaceIndent.length(); i < convertedLine.length(); i++ ) {
      if( convertedLine[i] == '\t' ) {
        size_t numSpaces = indentLength - ( i % indentLength );
        convertedLine.replace( i, 1, numSpaces, ' ' );
        i += indentLength - 1;
      }
    }
    return convertedLine;
  }

  void ASBeautifier::parseCurrentLine( const string& line ) {
    bool isInLineComment = false;
    bool isInOperator = false;
    bool isSpecialChar = false;
    bool haveCaseIndent = false;
    bool haveAssignmentThisLine = false;
    bool closingBraceReached = false;
    bool previousLineProbation = ( probationHeader != nullptr );
    char ch = ' ';
    int tabIncrementIn = 0;
    if( isInQuote
        && !haveLineContinuationChar
        && !isInVerbatimQuote
        && !isInAsm ) {
      isInQuote = false;
    }
    haveLineContinuationChar = false;
    for( size_t i = 0; i < line.length(); i++ ) {
      ch = line[i];
      if( isInBeautifySQL ) {
        continue;
      }
      if( isInQuote && !isInVerbatimQuote ) {
        if( isSpecialChar ) {
          isSpecialChar = false;
          continue;
        }
        if( line.compare( i, 2, "\\\\" ) == 0 ) {
          i++;
          continue;
        }
        if( ch == '\\' ) {
          if( peekNextChar( line, i ) == ' ' ) {
            haveLineContinuationChar = true;
          } else
          { isSpecialChar = true; }
          continue;
        }
      } else if( isInDefine && ch == '\\' ) {
        continue;
      }
      if( isWhiteSpace( ch ) ) {
        if( ch == '\t' ) {
          tabIncrementIn += convertTabToSpaces( i, tabIncrementIn );
        }
        continue;
      }
      if( !( isInComment || isInLineComment ) && ( ch == '"' || ( ch == '\'' && !isDigitSeparator( line, i ) ) ) ) {
        if( !isInQuote ) {
          quoteChar = ch;
          isInQuote = true;
          char prevCh = i > 0 ? line[i - 1] : ' ';
          if( isCStyle() && prevCh == 'R' ) {
            int parenPos = line.find( '(', i );
            if( parenPos != -1 ) {
              isInVerbatimQuote = true;
              verbatimDelimiter = line.substr( i + 1, parenPos - i - 1 );
            }
          } else if( isSharpStyle() && prevCh == '@' ) {
            isInVerbatimQuote = true;
          } else if( g_preprocessorCppExternCBrace == 2 && line.compare( i, 3, "\"C\"" ) == 0 ) {
            ++g_preprocessorCppExternCBrace;
          }
        } else if( isInVerbatimQuote && ch == '"' ) {
          if( isCStyle() ) {
            string delim = ')' + verbatimDelimiter;
            int delimStart = i - delim.length();
            if( delimStart > 0 && line.substr( delimStart, delim.length() ) == delim ) {
              isInQuote = false;
              isInVerbatimQuote = false;
            }
          } else if( isSharpStyle() ) {
            if( line.compare( i, 2, "\"\"" ) == 0 )
            { i++; }
            else {
              isInQuote = false;
              isInVerbatimQuote = false;
              continue;
            }
          }
        } else if( quoteChar == ch ) {
          isInQuote = false;
          isContinuation = true;
          continue;
        }
      }
      if( isInQuote ) {
        continue;
      }
      if( !( isInComment || isInLineComment ) && line.compare( i, 2, "//" ) == 0 ) {
        if( isCaseHeaderCommentIndent ) {
          --indentCount;
        }
        if( isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty() ) {
          indentCount += adjustIndentCountForBreakElseIfComments();
        }
        isInLineComment = true;
        i++;
        continue;
      } else if( !( isInComment || isInLineComment ) && line.compare( i, 2, "/*" ) == 0 ) {
        if( isCaseHeaderCommentIndent && lineOpensWithComment ) {
          --indentCount;
        }
        if( isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty() ) {
          indentCount += adjustIndentCountForBreakElseIfComments();
        }
        isInComment = true;
        i++;
        if( !lineOpensWithComment ) {
          blockCommentNoIndent = true;
        }
        continue;
      } else if( ( isInComment || isInLineComment ) && line.compare( i, 2, "*/" ) == 0 ) {
        size_t firstText = line.find_first_not_of( " \t" );
        if( isCaseHeaderCommentIndent && firstText == i ) {
          --indentCount;
        }
        if( firstText == i ) {
          if( isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty() ) {
            indentCount += adjustIndentCountForBreakElseIfComments();
          }
        }
        isInComment = false;
        i++;
        blockCommentNoIndent = false;
        continue;
      } else if( line[0] == '#' && isIndentedPreprocessor( line, i ) ) {
        isInLineComment = true;
      }
      if( isInLineComment ) {
        while( i + 1 < line.length() ) {
          i++;
        }
        continue;
      }
      if( isInComment ) {
        if( !lineOpensWithComment && isCaseHeaderCommentIndent ) {
          --indentCount;
        }
        if( !lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty() ) {
          indentCount += adjustIndentCountForBreakElseIfComments();
        }
        while( i + 1 < line.length() && line.compare( i + 1, 2, "*/" ) != 0 ) {
          i++;
        }
        continue;
      }
      if( probationHeader != nullptr ) {
        if( ( probationHeader == &AS_STATIC && ch == '{' )
            || ( probationHeader == &AS_SYNCHRONIZED && ch == '(' ) ) {
          isInHeader = true;
          headerStack->emplace_back( probationHeader );
          isInConditional = ( probationHeader == &AS_SYNCHRONIZED );
          isContinuation = false;
          if( previousLineProbation && ch == '{' && !( blockIndent && probationHeader == &AS_STATIC ) ) {
            ++indentCount;
            previousLineProbationTab = true;
          }
          previousLineProbation = false;
        }
        probationHeader = nullptr;
      }
      prevNonSpaceCh = currentNonSpaceCh;
      currentNonSpaceCh = ch;
      if( !isLegalNameChar( ch ) && ch != ',' && ch != ';' ) {
        prevNonLegalCh = currentNonLegalCh;
        currentNonLegalCh = ch;
      }
      if( isInHeader ) {
        isInHeader = false;
        currentHeader = headerStack->back();
      } else
      { currentHeader = nullptr; }
      if( isCStyle() && isInTemplate
          && ( ch == '<' || ch == '>' )
          && !( line.length() > i + 1 && line.compare( i, 2, ">=" ) == 0 ) ) {
        if( ch == '<' ) {
          ++templateDepth;
          continuationIndentStackSizeStack->push_back( continuationIndentStack->size() );
          registerContinuationIndent( line, i, spaceIndentCount, tabIncrementIn, 0, true );
        } else if( ch == '>' ) {
          popLastContinuationIndent();
          if( --templateDepth <= 0 ) {
            ch = ';';
            isInTemplate = false;
            templateDepth = 0;
          }
        }
      }
      if( ch == '(' || ch == '[' || ch == ')' || ch == ']' ) {
        if( ch == '(' || ch == '[' ) {
          isInOperator = false;
          if( ch == '('
              && !headerStack->empty()
              && headerStack->back() == &AS_STRUCT ) {
            headerStack->pop_back();
            isInClassHeader = false;
            if( line.find( AS_STRUCT, 0 ) > i )
            { indentCount -= classInitializerIndents; }
            if( indentCount < 0 )
            { indentCount = 0; }
          }
          if( parenDepth == 0 ) {
            parenStatementStack->push_back( isContinuation );
            isContinuation = true;
          }
          parenDepth++;
          if( ch == '[' ) {
            ++squareBracketCount;
            if( squareBracketCount == 1 && isCStyle() ) {
              isInObjCMethodCall = true;
              isInObjCMethodCallFirst = true;
            }
          }
          continuationIndentStackSizeStack->push_back( continuationIndentStack->size() );
          if( currentHeader != nullptr ) {
            registerContinuationIndent( line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true );
          } else
          { registerContinuationIndent( line, i, spaceIndentCount, tabIncrementIn, 0, true ); }
        } else if( ch == ')' || ch == ']' ) {
          if( ch == ']' ) {
            --squareBracketCount;
          }
          if( squareBracketCount <= 0 ) {
            squareBracketCount = 0;
            if( isInObjCMethodCall )
            { isImmediatelyPostObjCMethodCall = true; }
          }
          foundPreCommandHeader = false;
          parenDepth--;
          if( parenDepth == 0 ) {
            if( !parenStatementStack->empty() ) {
              isContinuation = parenStatementStack->back();
              parenStatementStack->pop_back();
            }
            isInAsm = false;
            isInConditional = false;
          }
          if( !continuationIndentStackSizeStack->empty() ) {
            popLastContinuationIndent();
            if( !parenIndentStack->empty() ) {
              int poppedIndent = parenIndentStack->back();
              parenIndentStack->pop_back();
              if( i == 0 )
              { spaceIndentCount = poppedIndent; }
            }
          }
        }
        continue;
      }
      if( ch == '{' ) {
        bool isBlockOpener = ( ( prevNonSpaceCh == '{' && braceBlockStateStack->back() )
                               || prevNonSpaceCh == '}'
                               || prevNonSpaceCh == ')'
                               || prevNonSpaceCh == ';'
                               || peekNextChar( line, i ) == '{'
                               || foundPreCommandHeader
                               || foundPreCommandMacro
                               || isInClassHeader
                               || ( isInClassInitializer && !isLegalNameChar( prevNonSpaceCh ) )
                               || isNonInStatementArray
                               || isInObjCMethodDefinition
                               || isInObjCInterface
                               || isSharpAccessor
                               || isSharpDelegate
                               || isInExternC
                               || isInAsmBlock
                               || getNextWord( line, i ) == AS_NEW
                               || ( isInDefine && ( prevNonSpaceCh == '(' || isLegalNameChar( prevNonSpaceCh ) ) ) );
        if( isInObjCMethodDefinition ) {
          objCColonAlignSubsequent = 0;
          isImmediatelyPostObjCMethodDefinition = true;
          if( lineBeginsWithOpenBrace ) {
            clearObjCMethodDefinitionAlignment();
          }
        }
        if( !isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum ) {
          if( headerStack->empty() ) {
            isBlockOpener = true;
          } else if( headerStack->back() == &AS_OPEN_BRACE
                     && headerStack->size() >= 2 ) {
            if( ( *headerStack )[headerStack->size() - 2] == &AS_NAMESPACE
                || ( *headerStack )[headerStack->size() - 2] == &AS_MODULE
                || ( *headerStack )[headerStack->size() - 2] == &AS_CLASS
                || ( *headerStack )[headerStack->size() - 2] == &AS_INTERFACE
                || ( *headerStack )[headerStack->size() - 2] == &AS_STRUCT
                || ( *headerStack )[headerStack->size() - 2] == &AS_UNION )
            { isBlockOpener = true; }
          } else if( headerStack->back() == &AS_NAMESPACE
                     || headerStack->back() == &AS_MODULE
                     || headerStack->back() == &AS_CLASS
                     || headerStack->back() == &AS_INTERFACE
                     || headerStack->back() == &AS_STRUCT
                     || headerStack->back() == &AS_UNION ) {
            isBlockOpener = true;
          }
        }
        if( !isBlockOpener && currentHeader != nullptr ) {
          for( size_t n = 0; n < nonParenHeaders->size(); n++ )
            if( currentHeader == ( *nonParenHeaders )[n] ) {
              isBlockOpener = true;
              break;
            }
        }
        braceBlockStateStack->push_back( isBlockOpener );
        if( !isBlockOpener ) {
          continuationIndentStackSizeStack->push_back( continuationIndentStack->size() );
          registerContinuationIndent( line, i, spaceIndentCount, tabIncrementIn, 0, true );
          parenDepth++;
          if( i == 0 ) {
            shouldIndentBracedLine = false;
          }
          isInEnumTypeID = false;
          continue;
        }
        ++lineOpeningBlocksNum;
        if( isInClassInitializer || isInEnumTypeID ) {
          if( lineBeginsWithOpenBrace ) {
            indentCount -= classInitializerIndents;
            if( !headerStack->empty()
                && ( *headerStack ).back() == &AS_CLASS ) {
              int nextChar = getNextProgramCharDistance( line, i );
              if( ( int ) line.length() > nextChar && line[nextChar] == '}' )
              { --indentCount; }
            }
          }
        }
        if( isInObjCInterface ) {
          isInObjCInterface = false;
          if( lineBeginsWithOpenBrace ) {
            --indentCount;
          }
        }
        if( braceIndent && !namespaceIndent && !headerStack->empty()
            && ( ( *headerStack ).back() == &AS_NAMESPACE
                 || ( *headerStack ).back() == &AS_MODULE ) ) {
          shouldIndentBracedLine = false;
          --indentCount;
        }
        if( !headerStack->empty()
            && ( *headerStack ).back() == &AS_STRUCT
            && isInIndentableStruct ) {
          ( *headerStack ).back() = &AS_CLASS;
        }
        squareBracketDepthStack->emplace_back( parenDepth );
        blockStatementStack->push_back( isContinuation );
        if( !continuationIndentStack->empty() ) {
          while( !continuationIndentStack->empty() ) {
            popLastContinuationIndent();
          }
          if( isInClassInitializer || isInClassHeaderTab ) {
            if( lineBeginsWithOpenBrace || lineBeginsWithComma )
            { spaceIndentCount = 0; }
          } else
          { spaceIndentCount = 0; }
        }
        blockTabCount += ( isContinuation ? 1 : 0 );
        if( g_preprocessorCppExternCBrace == 3 ) {
          ++g_preprocessorCppExternCBrace;
        }
        parenDepth = 0;
        isInClassHeader = false;
        isInClassHeaderTab = false;
        isInClassInitializer = false;
        isInEnumTypeID = false;
        isContinuation = false;
        isInQuestion = false;
        isInLet = false;
        foundPreCommandHeader = false;
        foundPreCommandMacro = false;
        isInExternC = false;
        tempStacks->emplace_back( new vector<const string*> );
        headerStack->emplace_back( &AS_OPEN_BRACE );
        lastLineHeader = &AS_OPEN_BRACE;
        continue;
      }
      bool isPotentialHeader = isCharPotentialHeader( line, i );
      if( isPotentialHeader && squareBracketCount == 0 ) {
        const string* newHeader = findHeader( line, i, headers );
        if( isCStyle() && ( newHeader == &AS_FOREVER || newHeader == &AS_FOREACH ) ) {
          if( line.find_first_of( "=;", i ) != string::npos ) {
            newHeader = nullptr;
          }
        } else if( newHeader == &AS_USING && ASBeautifier::peekNextChar( line, i + ( *newHeader ).length() - 1 ) != '(' ) {
          newHeader = nullptr;
        }
        if( newHeader != nullptr ) {
          bool isIndentableHeader = true;
          isInHeader = true;
          vector<const string*>* lastTempStack = nullptr;;
          if( !tempStacks->empty() ) {
            lastTempStack = tempStacks->back();
          }
          if( newHeader == &AS_IF && lastLineHeader == &AS_ELSE ) {
            headerStack->pop_back();
          } else if( newHeader == &AS_ELSE ) {
            if( lastTempStack != nullptr ) {
              int indexOfIf = indexOf( *lastTempStack, &AS_IF );
              if( indexOfIf != -1 ) {
                int restackSize = lastTempStack->size() - indexOfIf - 1;
                for( int r = 0; r < restackSize; r++ ) {
                  headerStack->emplace_back( lastTempStack->back() );
                  lastTempStack->pop_back();
                }
                if( !closingBraceReached )
                { indentCount += restackSize; }
              }
            }
          } else if( newHeader == &AS_WHILE ) {
            if( lastTempStack != nullptr ) {
              int indexOfDo = indexOf( *lastTempStack, &AS_DO );
              if( indexOfDo != -1 ) {
                int restackSize = lastTempStack->size() - indexOfDo - 1;
                for( int r = 0; r < restackSize; r++ ) {
                  headerStack->emplace_back( lastTempStack->back() );
                  lastTempStack->pop_back();
                }
                if( !closingBraceReached )
                { indentCount += restackSize; }
              }
            }
          } else if( newHeader == &AS_CATCH || newHeader == &AS_FINALLY ) {
            if( lastTempStack != nullptr ) {
              int indexOfTry = indexOf( *lastTempStack, &AS_TRY );
              if( indexOfTry == -1 )
              { indexOfTry = indexOf( *lastTempStack, &AS_CATCH ); }
              if( indexOfTry != -1 ) {
                int restackSize = lastTempStack->size() - indexOfTry - 1;
                for( int r = 0; r < restackSize; r++ ) {
                  headerStack->emplace_back( lastTempStack->back() );
                  lastTempStack->pop_back();
                }
                if( !closingBraceReached )
                { indentCount += restackSize; }
              }
            }
          } else if( newHeader == &AS_CASE ) {
            isInCase = true;
            if( !haveCaseIndent ) {
              haveCaseIndent = true;
              if( !lineBeginsWithOpenBrace )
              { --indentCount; }
            }
          } else if( newHeader == &AS_DEFAULT ) {
            isInCase = true;
            --indentCount;
          } else if( newHeader == &AS_STATIC
                     || newHeader == &AS_SYNCHRONIZED ) {
            if( !headerStack->empty()
                && ( headerStack->back() == &AS_STATIC
                     || headerStack->back() == &AS_SYNCHRONIZED ) )
            { isIndentableHeader = false; }
            else {
              isIndentableHeader = false;
              probationHeader = newHeader;
            }
          } else if( newHeader == &AS_TEMPLATE ) {
            isInTemplate = true;
            isIndentableHeader = false;
          }
          if( isIndentableHeader ) {
            headerStack->emplace_back( newHeader );
            isContinuation = false;
            if( indexOf( *nonParenHeaders, newHeader ) == -1 )
            { isInConditional = true; }
            lastLineHeader = newHeader;
          } else
          { isInHeader = false; }
          i += newHeader->length() - 1;
          continue;
        }
        if( findHeader( line, i, preCommandHeaders ) != nullptr ) {
          foundPreCommandHeader = true;
        }
        if( isCStyle() && findKeyword( line, i, AS_NS_DURING ) ) {
          foundPreCommandMacro = true;
        }
        if( isCStyle() && findKeyword( line, i, AS_NS_HANDLER ) ) {
          foundPreCommandMacro = true;
        }
        if( parenDepth == 0 && findKeyword( line, i, AS_ENUM ) ) {
          isInEnum = true;
        }
        if( isSharpStyle() && findKeyword( line, i, AS_LET ) ) {
          isInLet = true;
        }
      }
      if( ch == '?' ) {
        isInQuestion = true;
      }
      if( ch == ':' ) {
        if( line.length() > i + 1 && line[i + 1] == ':' ) { // look for ::
          ++i;
          continue;
        } else if( isInQuestion ) {
        } else if( parenDepth > 0 ) {
        } else if( isInEnum ) {
          isInEnumTypeID = true;
          if( i == 0 ) {
            indentCount += classInitializerIndents;
          }
        } else if( isCStyle()
                   && !isInCase
                   && ( prevNonSpaceCh == ')' || foundPreCommandHeader ) ) {
          isInClassInitializer = true;
          registerContinuationIndentColon( line, i, tabIncrementIn );
          if( i == 0 ) {
            indentCount += classInitializerIndents;
          }
        } else if( isInClassHeader || isInObjCInterface ) {
          isInClassHeaderTab = true;
          registerContinuationIndentColon( line, i, tabIncrementIn );
        } else if( isInAsm || isInAsmOneLine || isInAsmBlock ) {
        } else if( isDigit( peekNextChar( line, i ) ) ) {
        } else if( isCStyle() && isInClass && prevNonSpaceCh != ')' ) {
          --indentCount;
          if( modifierIndent ) {
            spaceIndentCount += ( indentLength / 2 );
          }
        } else if( isCStyle() && !isInClass
                   && headerStack->size() >= 2
                   && ( *headerStack )[headerStack->size() - 2] == &AS_CLASS
                   && ( *headerStack )[headerStack->size() - 1] == &AS_OPEN_BRACE ) {
        } else if( isJavaStyle() && lastLineHeader == &AS_FOR ) {
        } else {
          currentNonSpaceCh = ';';
          char peekedChar = peekNextChar( line, i );
          if( isInCase ) {
            isInCase = false;
            ch = ';';
          } else if( isCStyle() || ( isSharpStyle() && peekedChar == ';' ) ) {
            if( labelIndent )
            { --indentCount; }
            else if( !lineBeginsWithOpenBrace )
            { indentCount = 0; }
          }
        }
      }
      if( ( ch == ';' || ( parenDepth > 0 && ch == ',' ) ) && !continuationIndentStackSizeStack->empty() )
        while( ( int ) continuationIndentStackSizeStack->back() + ( parenDepth > 0 ? 1 : 0 )
               < ( int ) continuationIndentStack->size() ) {
          continuationIndentStack->pop_back();
        } else if( ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty() ) {
        continuationIndentStack->pop_back();
      }
      if( ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray ) {
        size_t nextChar = line.find_first_not_of( " \t", i + 1 );
        if( nextChar != string::npos ) {
          if( line.compare( nextChar, 2, "//" ) == 0
              || line.compare( nextChar, 2, "/*" ) == 0 ) {
            nextChar = string::npos;
          }
        }
        if( nextChar == string::npos ) {
          if( isJavaStyle() && isInClassHeader ) {
          } else if( !isInTemplate && !isInClassHeaderTab && !isInClassInitializer ) {
            int prevWord = getContinuationIndentComma( line, i );
            int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
            continuationIndentStack->emplace_back( continuationIndentCount );
            isContinuation = true;
          }
        }
      }
      if( ch == ',' && parenDepth == 0 && lineBeginsWithComma
          && ( isInClassInitializer || isInClassHeaderTab ) ) {
        spaceIndentCount = 0;
      }
      if( ( ch == ';' && parenDepth == 0 ) || ch == '}' ) {
        if( ch == '}' ) {
          if( braceBlockStateStack->size() > 1 ) {
            bool braceBlockState = braceBlockStateStack->back();
            braceBlockStateStack->pop_back();
            if( !braceBlockState ) {
              if( !continuationIndentStackSizeStack->empty() ) {
                popLastContinuationIndent();
                parenDepth--;
                if( i == 0 )
                { shouldIndentBracedLine = false; }
                if( !parenIndentStack->empty() ) {
                  int poppedIndent = parenIndentStack->back();
                  parenIndentStack->pop_back();
                  if( i == 0 )
                  { spaceIndentCount = poppedIndent; }
                }
              }
              continue;
            }
          }
          ++lineClosingBlocksNum;
          if( !continuationIndentStackSizeStack->empty() ) {
            popLastContinuationIndent();
          }
          if( !squareBracketDepthStack->empty() ) {
            parenDepth = squareBracketDepthStack->back();
            squareBracketDepthStack->pop_back();
            isContinuation = blockStatementStack->back();
            blockStatementStack->pop_back();
            if( isContinuation )
            { blockTabCount--; }
          }
          closingBraceReached = true;
          if( i == 0 ) {
            spaceIndentCount = 0;
          }
          isInAsmBlock = false;
          isInAsm = isInAsmOneLine = isInQuote = false;
          int headerPlace = indexOf( *headerStack, &AS_OPEN_BRACE );
          if( headerPlace != -1 ) {
            const string* popped = headerStack->back();
            while( popped != &AS_OPEN_BRACE ) {
              headerStack->pop_back();
              popped = headerStack->back();
            }
            headerStack->pop_back();
            if( headerStack->empty() )
            { g_preprocessorCppExternCBrace = 0; }
            if( !namespaceIndent && !headerStack->empty()
                && ( ( *headerStack ).back() == &AS_NAMESPACE
                     || ( *headerStack ).back() == &AS_MODULE )
                && i == 0 )
            { shouldIndentBracedLine = false; }
            if( !tempStacks->empty() ) {
              vector<const string*>* temp = tempStacks->back();
              tempStacks->pop_back();
              delete temp;
            }
          }
          ch = ' ';
        }
        if( !tempStacks->back()->empty() )
          while( !tempStacks->back()->empty() ) {
            tempStacks->back()->pop_back();
          }
        while( !headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE ) {
          tempStacks->back()->emplace_back( headerStack->back() );
          headerStack->pop_back();
        }
        if( parenDepth == 0 && ch == ';' ) {
          isContinuation = false;
        }
        if( isInObjCMethodDefinition ) {
          objCColonAlignSubsequent = 0;
          isImmediatelyPostObjCMethodDefinition = true;
        }
        previousLastLineHeader = nullptr;
        isInClassHeader = false;
        isInEnum = false;
        isInEnumTypeID = false;
        isInQuestion = false;
        isInTemplate = false;
        isInObjCInterface = false;
        foundPreCommandHeader = false;
        foundPreCommandMacro = false;
        squareBracketCount = 0;
        continue;
      }
      if( isPotentialHeader ) {
        if( !isInTemplate && !( isCStyle() && parenDepth > 0 ) ) {
          const string* newHeader = findHeader( line, i, preBlockStatements );
          if( newHeader == &AS_MODULE ) {
            char nextChar = peekNextChar( line, i + newHeader->length() - 1 );
            if( prevNonSpaceCh == ')' || !isalpha( nextChar ) )
            { newHeader = nullptr; }
          }
          if( newHeader != nullptr && !( isCStyle() && newHeader == &AS_CLASS && isInEnum ) ) {
            if( !isSharpStyle() )
            { headerStack->emplace_back( newHeader ); }
            else if( !( newHeader == &AS_WHERE
                        || ( ( newHeader == &AS_CLASS || newHeader == &AS_STRUCT )
                             && !headerStack->empty()
                             && ( headerStack->back() == &AS_CLASS
                                  || headerStack->back() == &AS_STRUCT ) ) ) )
            { headerStack->emplace_back( newHeader ); }
            if( !headerStack->empty() ) {
              if( ( *headerStack ).back() == &AS_CLASS
                  || ( *headerStack ).back() == &AS_STRUCT
                  || ( *headerStack ).back() == &AS_INTERFACE )
              { isInClassHeader = true; }
              else if( ( *headerStack ).back() == &AS_NAMESPACE
                       || ( *headerStack ).back() == &AS_MODULE ) {
                if( !continuationIndentStack->empty() )
                { continuationIndentStack->pop_back(); }
                isContinuation = false;
              }
            }
            i += newHeader->length() - 1;
            continue;
          }
        }
        const string* foundIndentableHeader = findHeader( line, i, indentableHeaders );
        if( foundIndentableHeader != nullptr ) {
          i += foundIndentableHeader->length() - 1;
          if( !isInOperator && !isInTemplate && !isNonInStatementArray ) {
            registerContinuationIndent( line, i, spaceIndentCount, tabIncrementIn, 0, false );
            isContinuation = true;
          }
          continue;
        }
        if( isCStyle() && findKeyword( line, i, AS_OPERATOR ) ) {
          isInOperator = true;
        }
        if( g_preprocessorCppExternCBrace == 1 && findKeyword( line, i, AS_EXTERN ) ) {
          ++g_preprocessorCppExternCBrace;
        }
        if( g_preprocessorCppExternCBrace == 3 ) {
          g_preprocessorCppExternCBrace = 0;
        }
        if( findKeyword( line, i, AS_NEW ) ) {
          if( isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=' ) {
            continuationIndentStack->back() = 0;
          }
        }
        if( isCStyle() ) {
          if( findKeyword( line, i, AS_ASM )
              || findKeyword( line, i, AS__ASM__ ) ) {
            isInAsm = true;
          } else if( findKeyword( line, i, AS_MS_ASM )
                     || findKeyword( line, i, AS_MS__ASM ) ) {
            int index = 4;
            if( peekNextChar( line, i ) == '_' )
            { index = 5; }
            char peekedChar = peekNextChar( line, i + index );
            if( peekedChar == '{' || peekedChar == ' ' )
            { isInAsmBlock = true; }
            else
            { isInAsmOneLine = true; }
          }
        }
        string name = getCurrentWord( line, i );
        i += name.length() - 1;
        continue;
      }
      if( ch == '@' && !isWhiteSpace( line[i + 1] ) && isCharPotentialHeader( line, i + 1 ) ) {
        string curWord = getCurrentWord( line, i + 1 );
        if( curWord == AS_INTERFACE && headerStack->empty() ) {
          isInObjCInterface = true;
          string name = '@' + curWord;
          i += name.length() - 1;
          continue;
        } else if( isInObjCInterface ) {
          --indentCount;
          isInObjCInterface = false;
        }
        if( curWord == AS_PUBLIC
            || curWord == AS_PRIVATE
            || curWord == AS_PROTECTED ) {
          --indentCount;
          if( modifierIndent ) {
            spaceIndentCount += ( indentLength / 2 );
          }
          string name = '@' + curWord;
          i += name.length() - 1;
          continue;
        } else if( curWord == AS_END ) {
          popLastContinuationIndent();
          spaceIndentCount = 0;
          isInObjCMethodDefinition = false;
          string name = '@' + curWord;
          i += name.length() - 1;
          continue;
        }
      } else if( ( ch == '-' || ch == '+' )
                 && peekNextChar( line, i ) == '('
                 && headerStack->empty()
                 && line.find_first_not_of( " \t" ) == i ) {
        if( isInObjCInterface ) {
          --indentCount;
        }
        isInObjCInterface = false;
        isInObjCMethodDefinition = true;
        continue;
      }
      bool isPotentialOperator = isCharPotentialOperator( ch );
      if( isPotentialOperator ) {
        const string* foundAssignmentOp = findOperator( line, i, assignmentOperators );
        const string* foundNonAssignmentOp = findOperator( line, i, nonAssignmentOperators );
        if( foundNonAssignmentOp != nullptr ) {
          if( foundNonAssignmentOp == &AS_LAMBDA ) {
            foundPreCommandHeader = true;
          }
          if( isInTemplate && foundNonAssignmentOp == &AS_GR_GR ) {
            foundNonAssignmentOp = nullptr;
          }
        }
        if( foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr ) {
          if( foundAssignmentOp->length() < foundNonAssignmentOp->length() ) {
            foundAssignmentOp = nullptr;
          } else
          { foundNonAssignmentOp = nullptr; }
        }
        if( foundNonAssignmentOp != nullptr ) {
          if( foundNonAssignmentOp->length() > 1 ) {
            i += foundNonAssignmentOp->length() - 1;
          }
          if( !isInOperator
              && continuationIndentStack->empty()
              && isCStyle()
              && ( foundNonAssignmentOp == &AS_GR_GR
                   || foundNonAssignmentOp == &AS_LS_LS ) ) {
            if( i < 2 && spaceIndentCount == 0 )
            { spaceIndentCount += 2 * indentLength; }
            registerContinuationIndent( line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false );
          }
        } else if( foundAssignmentOp != nullptr ) {
          foundPreCommandHeader = false;
          foundPreCommandMacro = false;
          if( foundAssignmentOp->length() > 1 ) {
            i += foundAssignmentOp->length() - 1;
          }
          if( !isInOperator && !isInTemplate && ( !isNonInStatementArray || isInEnum ) ) {
            if( foundAssignmentOp == &AS_ASSIGN && prevNonSpaceCh != ']' && statementEndsWithComma( line, i ) ) {
              if( !haveAssignmentThisLine ) {
                haveAssignmentThisLine = true;
                int prevWordIndex = getContinuationIndentAssign( line, i );
                int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
                continuationIndentStack->emplace_back( continuationIndentCount );
                isContinuation = true;
              }
            } else if( isInLet )
            { isInLet = false; }
            else if( !lineBeginsWithComma ) {
              if( i == 0 && spaceIndentCount == 0 )
              { spaceIndentCount += indentLength; }
              registerContinuationIndent( line, i, spaceIndentCount, tabIncrementIn, 0, false );
              isContinuation = true;
            }
          }
        }
      }
    }
  }
}
